﻿using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HARTCalibrationTool.Commands.PressureController
{
    public enum PressureControllerCMDsType
    { 
        eSetUnit = 0x01,
        eQueryUnit = 0x02,

        eSetPressure = 0x03,
        eQueryPressure = 0x04,

        ePressurization = 0x05,
        ePressureRelief = 0x06,

        eQueryCurActPressure = 0x07,
    }

    public abstract class PressureControllerCMDsBase : CommandsBase
    {
        public PressureControllerCMDsBase(SerialPortsBase serialPortManager, string commandName) : base(serialPortManager, commandName)
        {

        }
        public override async Task ExecuteCMD()
        {
            await SendCMD();
        }

        public override async Task ParseResponse(byte[] data)
        {
            await Task.Run(() => { });
        }

        protected abstract Task SendCMD();

        public override VerifyDataFrameStatus VerifyDataFrameIntegrity(byte[] data)
        {
            int len = data.Length;

            if (len > 2)
            {
                if ((data[len - 2] == 13) && (data[len - 1] == 10)) // "\r\n"
                {
                    return VerifyDataFrameStatus.eSuccess;
                }
            }

            return VerifyDataFrameStatus.eWaiting;
        }
    }

    public class PressureControllerCMDs : PressureControllerCMDsBase
    {
        private PressureControllerCMDsType _cmd;
        private object[] _args;

        public PressureControllerCMDs(SerialPortsBase serialPortManager, string commandName, PressureControllerCMDsType cmd, object[] args) : base(serialPortManager, commandName)
        {
            _cmd = cmd;
            _args = args;
        }

        protected override async Task SendCMD()
        {
            string cmdString = null;
            string arg = null;

            if (_cmd == PressureControllerCMDsType.eSetUnit)
            {
                arg = (string)_args[0];

                cmdString = $":UNIT {arg}\r\n";
            }
            else if (_cmd == PressureControllerCMDsType.eQueryUnit)
            {
                cmdString = ":UNIT?\r\n";
            }
            else if (_cmd == PressureControllerCMDsType.eSetPressure)
            {
                arg = (string)_args[0];
                float tempValue;

                if (float.TryParse(arg, out tempValue))
                {
                    cmdString = $":SOUR {arg}\r\n";
                }
                else
                {
                    MessageBox.Show("压力值{" + arg + "}格式错误", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                    return;
                }
            }
            else if (_cmd == PressureControllerCMDsType.eQueryPressure)
            {
                cmdString = ":SOUR?\r\n";
            }
            else if (_cmd == PressureControllerCMDsType.ePressurization)
            {
                cmdString = ":OUTP 1\r\n";
            }
            else if (_cmd == PressureControllerCMDsType.ePressureRelief)
            {
                cmdString = ":OUTP 0\r\n";
            }
            else if (_cmd == PressureControllerCMDsType.eQueryCurActPressure)
            {
                cmdString = ":SENS:PRES?\r\n";
            }

            SerialPortsBase.PrintMessage("--> " + cmdString);

            await SerialPortMager.SerialPortWriteLine(cmdString);
        }

        public override async Task ParseResponse(byte[] data)
        {
            await Task.Run(() => {
                SerialPortsBase.PrintMessage("<-- " + Encoding.UTF8.GetString(data));
            });
        }

        public override void OnFailure()
        {

        }

        public override void OnSuccess()
        {

        }

        public override void OnTimeout()
        {

        }
    }

    public class AutoCaliPressureControllerCMDs : PressureControllerCMDs
    {
        private PressureControllerCMDsType _cmd;
        private object[] _args;

        public AutoCaliPressureControllerCMDs(SerialPortsBase serialPortManager, string commandName, PressureControllerCMDsType cmd, object[] args = null) : base(serialPortManager, commandName, cmd, args)
        {
            _cmd = cmd;
            _args = args;
        }

        public override async Task ParseResponse(byte[] data)
        {
            string responseStr = Encoding.UTF8.GetString(data);

            await Task.Run(() => {
                if (_cmd == PressureControllerCMDsType.eSetUnit)
                {
                    //if (responseStr == "OK:POWER,ON\r\n")
                    //{
                    //    CommandExeSuccess();
                    //    SetCurrentCMDResponseFinishedFlg();
                    //}
                }
                else if (_cmd == PressureControllerCMDsType.eSetPressure)
                {
                    //if (responseStr.Contains("OK:TEMP,S"))
                    //{
                    //    CommandExeSuccess();
                    //    SetCurrentCMDResponseFinishedFlg();
                    //}
                }
                else if (_cmd == PressureControllerCMDsType.eQueryCurActPressure)
                { 
                    string pattern = @"^:SENS:PRES\s+(-?\d+(\.\d+)?)\r\n$";

                    Match match = Regex.Match(responseStr, pattern);

                    if (match.Success)
                    {
                        double pressure = double.Parse(match.Groups[1].Value);
                        double error = (double)_args[0];
                        double targetPressure = double.Parse((string)_args[1]);

                        if (Math.Abs(pressure - targetPressure) < error)
                        {
                            CommandExeSuccess();
                            SetCurrentCMDResponseFinishedFlg();
                        }
                    }
                }
                else if (_cmd == PressureControllerCMDsType.eQueryUnit)
                {
                    if (responseStr == ":UNIT:PRES KPA\r\n")
                    {
                        CommandExeSuccess();
                        SetCurrentCMDResponseFinishedFlg();
                    }
                }

                MainUI.loggerDebugMsg("<--" + responseStr);
                SerialPortsBase.PrintMessage("<-- " + responseStr);
            });
        }
    }
}
